{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "计算收盘价减去移动平均值（CMMA），可用于 均值回归 策略"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from numba import njit  #Numba，这是一个即时编译器，可以将 Python 代码转换为高效的机器代码。\n",
    "import pybroker"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "用于计算收盘价的\"Current Minus Moving Average\"（当前值减去移动平均值），这是一种常用的金融指标，用于识别价格趋势和波动。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义一个函数cmma，它接受两个参数：bar_data（代表某种数据序列，如股票的价格数据）\n",
    "# bar_data，它是一个包含 OHLCV 数据和自定义字段的 BarData 类实例；\n",
    "# 和lookback（一个整数，表示计算移动平均值的周期）。lookback，它是一个用户定义的参数，用于移动平均值的回溯期。\n",
    "def cmma(bar_data, lookback):\n",
    "\n",
    "    @njit  # Enable Numba JIT.\n",
    "    def vec_cmma(values):   #vec_cmma(values)：这是一个内部函数，用于计算移动平均的差值序列。\n",
    "        # Initialize the result array.\n",
    "        n = len(values)\n",
    "        out = np.array([np.nan for _ in range(n)])# 初始化一个长度与输入数据相同的结果数组out，并填充NaN（非数字）值。\n",
    "\n",
    "        # For all bars starting at lookback:\n",
    "        for i in range(lookback, n):    #遍历数据，从lookback位置开始到最后，对于每个位置i\n",
    "            # Calculate the moving average for the lookback.\n",
    "            # 计算从i-lookback到i这段时间窗口内的收盘价的平均值（移动平均）。\n",
    "            ma = 0\n",
    "            for j in range(i - lookback, i):\n",
    "                ma += values[j]\n",
    "            ma /= lookback\n",
    "            # Subtract the moving average from value.\n",
    "            #将当前位置的收盘价减去计算出的移动平均值，并将结果存储在out数组中对应的位置。\n",
    "            out[i] = values[i] - ma\n",
    "        return out\n",
    "\n",
    "    # Calculate with close prices\n",
    "    # 调用vec_cmma(bar_data.close)来实际计算收盘价的移动平均差值序列，并返回这个序列。\n",
    "    return vec_cmma(bar_data.close)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'指标函数中在 bar_data 之后的任何参数都将作为用户定义的参数传递给 pybroker.indicator。\\n一旦指标函数在 PyBroker 中注册，它将返回一个新的 Indicator 实例，该实例引用我们定义的指标函数。'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "# 我们将指标函数命名为 cmma_20，并将 回溯 参数指定为 20 条。\n",
    "cmma_20 = pybroker.indicator('cmma_20', cmma, lookback=20)\n",
    "'''指标函数中在 bar_data 之后的任何参数都将作为用户定义的参数传递给 pybroker.indicator。\n",
    "一旦指标函数在 PyBroker 中注册，它将返回一个新的 Indicator 实例，该实例引用我们定义的指标函数。'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loaded cached bar data.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# from pybroker import YFinance\n",
    "from pybroker.ext.data import AKShare\n",
    "pybroker.enable_data_source_cache('AKShare')\n",
    "\n",
    "aKShare = AKShare()\n",
    "df = aKShare.query('000001', '4/1/2020', '4/1/2022')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2020-04-01       NaN\n",
       "2020-04-02       NaN\n",
       "2020-04-03       NaN\n",
       "2020-04-07       NaN\n",
       "2020-04-08       NaN\n",
       "               ...  \n",
       "2022-03-28   -0.0155\n",
       "2022-03-29   -0.1405\n",
       "2022-03-30    0.4515\n",
       "2022-03-31    0.6450\n",
       "2022-04-01    1.0315\n",
       "Length: 487, dtype: float64"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cmma_20(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.3097499999999993"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Indicator 类还提供了用于衡量其信息含量的函数。例如，您可以计算 四分位距（IQR）：\n",
    "cmma_20.iqr(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7386119114025429"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 计算相对熵：\n",
    "cmma_20.relative_entropy(df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 在策略中使用指标\n",
    "在实现我们的指标之后，下一步是将其整合到交易策略中。以下示例展示了一个简单的策略，当 20 日 CMMA 小于 0 时进行多头建仓 — 即当最近收盘价跌破 20 日移动平均线时："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def buy_cmma_cross(ctx):\n",
    "    if ctx.long_pos():\n",
    "        return\n",
    "    # Place a buy order if the most recent value of the 20 day CMMA is < 0:\n",
    "    if ctx.indicator('cmma_20')[-1] < 0:\n",
    "        ctx.buy_shares = ctx.calc_target_shares(1)\n",
    "        ctx.hold_bars = 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pybroker import Strategy\n",
    "\n",
    "strategy = Strategy(aKShare, '4/1/2020', '4/1/2022')\n",
    "strategy.add_execution(buy_cmma_cross, '000001', indicators=cmma_20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<diskcache.core.Cache at 0x1719b370790>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pybroker.enable_indicator_cache('my_indicators')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Backtesting: 2020-04-01 00:00:00 to 2022-04-01 00:00:00\n",
      "\n",
      "Loaded cached bar data.\n",
      "\n",
      "Loaded cached indicator data.\n",
      "\n",
      "Test split: 2020-04-01 00:00:00 to 2022-04-01 00:00:00\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0% (0 of 487) |                        | Elapsed Time: 0:00:00 ETA:  --:--:--\n",
      "  8% (41 of 487) |#                      | Elapsed Time: 0:00:00 ETA:   0:00:01\n",
      " 12% (61 of 487) |##                     | Elapsed Time: 0:00:00 ETA:   0:00:01\n",
      " 26% (131 of 487) |#####                 | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 47% (231 of 487) |##########            | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 51% (251 of 487) |###########           | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 65% (321 of 487) |##############        | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 82% (401 of 487) |##################    | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      " 92% (451 of 487) |####################  | Elapsed Time: 0:00:00 ETA:   0:00:00\n",
      "100% (487 of 487) |######################| Elapsed Time: 0:00:00 Time:  0:00:00\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Finished backtest: 0:00:06\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>trade_count</td>\n",
       "      <td>67.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>initial_market_value</td>\n",
       "      <td>100000.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>end_market_value</td>\n",
       "      <td>111794.0400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>total_pnl</td>\n",
       "      <td>11794.0400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>unrealized_pnl</td>\n",
       "      <td>0.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>total_return_pct</td>\n",
       "      <td>11.7940</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>total_profit</td>\n",
       "      <td>128044.3800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>total_loss</td>\n",
       "      <td>-116250.3400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>total_fees</td>\n",
       "      <td>0.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>max_drawdown</td>\n",
       "      <td>-45748.9000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>max_drawdown_pct</td>\n",
       "      <td>-31.2460</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>win_rate</td>\n",
       "      <td>48.4848</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>loss_rate</td>\n",
       "      <td>51.5152</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>winning_trades</td>\n",
       "      <td>32.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>losing_trades</td>\n",
       "      <td>34.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>avg_pnl</td>\n",
       "      <td>176.0304</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>avg_return_pct</td>\n",
       "      <td>0.2491</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>avg_trade_bars</td>\n",
       "      <td>3.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>avg_profit</td>\n",
       "      <td>4001.3869</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>avg_profit_pct</td>\n",
       "      <td>3.4772</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>avg_winning_trade_bars</td>\n",
       "      <td>3.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>avg_loss</td>\n",
       "      <td>-3419.1276</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>avg_loss_pct</td>\n",
       "      <td>-2.7818</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>avg_losing_trade_bars</td>\n",
       "      <td>3.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>largest_win</td>\n",
       "      <td>16217.8000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>largest_win_pct</td>\n",
       "      <td>13.0200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>largest_win_bars</td>\n",
       "      <td>3.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>largest_loss</td>\n",
       "      <td>-14423.6400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>largest_loss_pct</td>\n",
       "      <td>-11.4400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>largest_loss_bars</td>\n",
       "      <td>3.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>max_wins</td>\n",
       "      <td>3.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>max_losses</td>\n",
       "      <td>4.0000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32</th>\n",
       "      <td>sharpe</td>\n",
       "      <td>0.0144</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>33</th>\n",
       "      <td>sortino</td>\n",
       "      <td>0.0149</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>34</th>\n",
       "      <td>profit_factor</td>\n",
       "      <td>1.0570</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35</th>\n",
       "      <td>ulcer_index</td>\n",
       "      <td>3.8502</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>36</th>\n",
       "      <td>upi</td>\n",
       "      <td>0.0085</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37</th>\n",
       "      <td>equity_r2</td>\n",
       "      <td>0.1555</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38</th>\n",
       "      <td>std_error</td>\n",
       "      <td>12537.6857</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                      name        value\n",
       "0              trade_count      67.0000\n",
       "1     initial_market_value  100000.0000\n",
       "2         end_market_value  111794.0400\n",
       "3                total_pnl   11794.0400\n",
       "4           unrealized_pnl       0.0000\n",
       "5         total_return_pct      11.7940\n",
       "6             total_profit  128044.3800\n",
       "7               total_loss -116250.3400\n",
       "8               total_fees       0.0000\n",
       "9             max_drawdown  -45748.9000\n",
       "10        max_drawdown_pct     -31.2460\n",
       "11                win_rate      48.4848\n",
       "12               loss_rate      51.5152\n",
       "13          winning_trades      32.0000\n",
       "14           losing_trades      34.0000\n",
       "15                 avg_pnl     176.0304\n",
       "16          avg_return_pct       0.2491\n",
       "17          avg_trade_bars       3.0000\n",
       "18              avg_profit    4001.3869\n",
       "19          avg_profit_pct       3.4772\n",
       "20  avg_winning_trade_bars       3.0000\n",
       "21                avg_loss   -3419.1276\n",
       "22            avg_loss_pct      -2.7818\n",
       "23   avg_losing_trade_bars       3.0000\n",
       "24             largest_win   16217.8000\n",
       "25         largest_win_pct      13.0200\n",
       "26        largest_win_bars       3.0000\n",
       "27            largest_loss  -14423.6400\n",
       "28        largest_loss_pct     -11.4400\n",
       "29       largest_loss_bars       3.0000\n",
       "30                max_wins       3.0000\n",
       "31              max_losses       4.0000\n",
       "32                  sharpe       0.0144\n",
       "33                 sortino       0.0149\n",
       "34           profit_factor       1.0570\n",
       "35             ulcer_index       3.8502\n",
       "36                     upi       0.0085\n",
       "37               equity_r2       0.1555\n",
       "38               std_error   12537.6857"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result = strategy.backtest(warmup=20) #warmup 参数指定在运行回测执行之前需要经过 20 个 Bar：\n",
    "result.metrics_df.round(4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 向量化辅助函数\n",
    "PyBroker 库提供了向量化辅助函数，以简化计算指标的过程。其中一个辅助函数是 highv，它用于计算每个 n 条 Bar 周期的最高值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2020-04-01      NaN\n",
       "2020-04-02      NaN\n",
       "2020-04-03      NaN\n",
       "2020-04-07      NaN\n",
       "2020-04-08    13.13\n",
       "              ...  \n",
       "2022-03-28    15.31\n",
       "2022-03-29    15.31\n",
       "2022-03-30    15.31\n",
       "2022-03-31    15.57\n",
       "2022-04-01    15.79\n",
       "Length: 487, dtype: float64"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 定义了一个名为 hhv 的指标函数，该函数使用 highv 计算每个 5 条 Bar 周期的*最高*价格：\n",
    "from pybroker import highv\n",
    "\n",
    "def hhv(bar_data, period):\n",
    "    return highv(bar_data.high, period)\n",
    "\n",
    "hhv_5 = pybroker.indicator('hhv_5', hhv, period=5)\n",
    "hhv_5(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2020-04-01      NaN\n",
       "2020-04-02      NaN\n",
       "2020-04-03      NaN\n",
       "2020-04-07      NaN\n",
       "2020-04-08    13.13\n",
       "              ...  \n",
       "2022-03-28    15.31\n",
       "2022-03-29    15.31\n",
       "2022-03-30    15.31\n",
       "2022-03-31    15.57\n",
       "2022-04-01    15.79\n",
       "Length: 487, dtype: float64"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 此外，PyBroker 还为最高和最低指标提供了方便的封装。我们的 hhv 指标可以重写为\n",
    "from pybroker import highest\n",
    "\n",
    "hhv_5 = highest('hhv_5', 'high', period=5)\n",
    "hhv_5(df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 计算多个指标\n",
    "可以使用 IndicatorSet 来计算多个指标。通过将 cmma_20 和 hhv_5 指标添加到 IndicatorSet 中，可以一起计算它们。最终输出将是一个包含两者的 Pandas DataFrame ："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Computing indicators...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0% (0 of 2) |                          | Elapsed Time: 0:00:00 ETA:  --:--:--\n",
      " 50% (1 of 2) |#############             | Elapsed Time: 0:00:09 ETA:   0:00:09\n",
      "100% (2 of 2) |##########################| Elapsed Time: 0:00:09 Time:  0:00:09\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>symbol</th>\n",
       "      <th>date</th>\n",
       "      <th>cmma_20</th>\n",
       "      <th>hhv_5</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>000001</td>\n",
       "      <td>2020-04-01</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>000001</td>\n",
       "      <td>2020-04-02</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>000001</td>\n",
       "      <td>2020-04-03</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>000001</td>\n",
       "      <td>2020-04-07</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>000001</td>\n",
       "      <td>2020-04-08</td>\n",
       "      <td>NaN</td>\n",
       "      <td>13.13</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>482</th>\n",
       "      <td>000001</td>\n",
       "      <td>2022-03-28</td>\n",
       "      <td>-0.0155</td>\n",
       "      <td>15.31</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>483</th>\n",
       "      <td>000001</td>\n",
       "      <td>2022-03-29</td>\n",
       "      <td>-0.1405</td>\n",
       "      <td>15.31</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>484</th>\n",
       "      <td>000001</td>\n",
       "      <td>2022-03-30</td>\n",
       "      <td>0.4515</td>\n",
       "      <td>15.31</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>485</th>\n",
       "      <td>000001</td>\n",
       "      <td>2022-03-31</td>\n",
       "      <td>0.6450</td>\n",
       "      <td>15.57</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>486</th>\n",
       "      <td>000001</td>\n",
       "      <td>2022-04-01</td>\n",
       "      <td>1.0315</td>\n",
       "      <td>15.79</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>487 rows × 4 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "     symbol       date  cmma_20  hhv_5\n",
       "0    000001 2020-04-01      NaN    NaN\n",
       "1    000001 2020-04-02      NaN    NaN\n",
       "2    000001 2020-04-03      NaN    NaN\n",
       "3    000001 2020-04-07      NaN    NaN\n",
       "4    000001 2020-04-08      NaN  13.13\n",
       "..      ...        ...      ...    ...\n",
       "482  000001 2022-03-28  -0.0155  15.31\n",
       "483  000001 2022-03-29  -0.1405  15.31\n",
       "484  000001 2022-03-30   0.4515  15.31\n",
       "485  000001 2022-03-31   0.6450  15.57\n",
       "486  000001 2022-04-01   1.0315  15.79\n",
       "\n",
       "[487 rows x 4 columns]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from pybroker import IndicatorSet\n",
    "\n",
    "indicator_set = IndicatorSet()\n",
    "indicator_set.add(cmma_20, hhv_5)\n",
    "indicator_set(df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用 TA-Lib\n",
    "TA-Lib 是一个广泛使用的技术分析库，实现了许多金融指标。将 TA-Lib 与 PyBroker 集成非常简单。以下是一个示例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2020-04-01          NaN\n",
       "2020-04-02          NaN\n",
       "2020-04-03          NaN\n",
       "2020-04-07          NaN\n",
       "2020-04-08          NaN\n",
       "                ...    \n",
       "2022-03-28    44.426203\n",
       "2022-03-29    43.129524\n",
       "2022-03-30    48.100689\n",
       "2022-03-31    49.588508\n",
       "2022-04-01    52.695367\n",
       "Length: 487, dtype: float64"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import talib\n",
    "\n",
    "rsi_20 = pybroker.indicator('rsi_20', lambda data: talib.RSI(data.close, timeperiod=20))\n",
    "rsi_20(df)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pybroker",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
